﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LinFu.IoC.Configuration;
using LinFu.IoC.Configuration;

namespace CoreEx.Database.Query
{
    [Implements(typeof(ISelectExpression))]
    public class SelectQueryExpression : QueryExpression<SelectQueryExpression>,ISelectExpression
    {
        private IExpression _projectionExpression;
        private IExpression _groupByExpression;
        private IExpression _orderByExpression;
        private IExpression _intoExpression;        
        private bool _isSubQuery;


        public SelectQueryExpression(IExpression projectionExpression,IExpressionFactory expressionFactory) :base(expressionFactory)
        {
            _projectionExpression = projectionExpression;
        }

       
        #region ISelectExpression Members

        int ISelectExpression.TakeCount { get; set;}


        int ISelectExpression.SkipCount { get; set;}
        

        IExpression ISelectExpression.ProjectionExpression
        {
            get { return _projectionExpression; }
            set { _projectionExpression = value; }
        }

        IExpression ISelectExpression.GroupByExpression
        {
            get { return _groupByExpression; }
        }

        IExpression ISelectExpression.OrderByExpression
        {
            get { return _orderByExpression; }
        }

        IExpression ISelectExpression.IntoExpression
        {
            get { return _intoExpression; }
        }

        bool ISelectExpression.IsSubQuery
        {
            get { return _isSubQuery; }
            set { _isSubQuery = value; }
        }

        #endregion

        #region ISelectQuery Members

      

        public ISelectQueryExpression GroupBy(params IExpression[] expressions)
        {

            _groupByExpression = expressions.WrapExpressionList();
            return (ISelectQueryExpression)this;
        }

        public SelectQueryExpression OrderBy(IExpression expression, SortDirection direction)
        {
            if (!(expression is IOrderByExpression))            
                expression = ExpressionFactory.OrderBy(expression, direction);

            if (_orderByExpression == null)
            {
                _orderByExpression = expression;
                return this;
            }

            IExpressionList list = (_orderByExpression as IExpressionList);
            if (list == null)
            {
                list = (IExpressionList)ExpressionFactory.List(new[] { _orderByExpression });
                _orderByExpression = list;
            }

            list.Add(expression);
            return this;
        }

        public SelectQueryExpression OrderBy(IExpression expression)
        {
            OrderBy(expression, SortDirection.Ascending);
            return this;            
        }

        public SelectQueryExpression OrderBy(Func<IExpressionFactory, IExpression> expression)
        {
            OrderBy(expression(ExpressionFactory));                                    
            return this;
        }

        public SelectQueryExpression OrderBy(Func<IExpressionFactory, IExpression> expression, SortDirection direction)
        {
            OrderBy(expression(ExpressionFactory),direction);
            return this;
        }


        public ISelectQueryExpression Select(params IExpression[] expressions)
        {
            _projectionExpression = expressions.WrapExpressionList();
            return (ISelectQueryExpression)this;
        }

        public ISelectQueryExpression Select(params Func<IExpressionFactory, IOrderByExpression>[] expressions)
        {
            _projectionExpression = expressions.Select(e => e(ExpressionFactory)).Cast<IExpression>().ToArray().WrapExpressionList();
            return (ISelectQueryExpression)this;
        }

        public SelectQueryExpression Take(int count)
        {
            ((ISelectExpression) this).TakeCount = count;
            return this;
        }

        public SelectQueryExpression Skip(int count)
        {
            ((ISelectExpression)this).SkipCount = count;
            return this;
        }


        #endregion
    }
}